package model.cuota;

import model.prestamos.Imprimible;
import model.utilitarios.FechaDelDia;
import model.utilitarios.HTMLParser;
import model.utilitarios.XMLParser;

import org.joda.time.LocalDate;

/**
 * Representa las cuotas de los prestamos.
 * @author Lucas
 */
public abstract class Cuota implements Imprimible {

	private CuotaEstado estado;
	private double coeficienteSeguroVida;
	private double TEM;
	
	private int cuotaNumero;
	private LocalDate vencimiento;
	private double amortizacion;
	private double interes;
	private double saldoDeDeuda;
	private double seguro;
	private double gastosMensuales;
	private double valorCuota;
	private double valorTotalCuota;
	private LocalDate fechaDePago;
	private double interesPorMora;

	
	
	public Cuota(double valorCuota ,  int numeroDeCuota, LocalDate vencimiento, double gastosMensuales, double TEM, double coeficienteSeguroDeVida) {
		this.estado = new CuotaImpaga();
		this.TEM = TEM;
		this.coeficienteSeguroVida = coeficienteSeguroDeVida / 100;
		this.setGastosMensuales(gastosMensuales);
		this.setValorCuota(valorCuota);
		this.setCuotaNumero(numeroDeCuota);
		this.setVencimiento(vencimiento);
	}
	
	protected abstract void calcularInteres();
	protected abstract void calcularSaldoDeDeuda();
	protected abstract void calcularSeguro();
	
	/**
	 * Inicializa los valores de la cuota haciendo los respectivos calculos
	 * Las llamadas estan hechas en un orden estricto de manera que los calculos de metodos posteriores consumen los resultados de las operaciones previas
	 * Cualquier modificacion a este orden sin la debida precaucion puede provocar alteraciones en los valores de la cuota o en errores en el sistema.
	 */
	protected void calcularValoresCuota() {
		this.calcularInteres();
		this.calcularAmortizacion();
		this.calcularSaldoDeDeuda();
		this.calcularSeguro();
		this.calcularValorTotalCuota();
		this.calcularInteresPorMora();
	}
	
	
	/**
	 * Calcula el  interes por mora que se expresa como 
	 * valor total cuota * TEM
	 */
	private void calcularInteresPorMora() {
		this.setInteresPorMora(this.getValorTotalCuota() * TEM );
	}

	
	/**
	 * Calcula la amortizacion de la cuota que se expresa como:
	 * Valor cuota - interes
	 */
	private void calcularAmortizacion() {
		this.setAmortizacion(this.getValorCuota() - this.getInteres());
	}

	public double getAmortizacion() {
		return amortizacion;
	}

	/**
	 * Calcula el valor total de la cuota, que esta definido como:
	 * valor cuota + seguro + gastos mensuales
	 */
	private void calcularValorTotalCuota() {
		double valorTotalCuota = this.getValorCuota() + this.getSeguro() + this.getGastosMensuales(); 
		this.setValorTotalCuota(valorTotalCuota);
	}

	/**
	 * Pago de la cuota
	 */
	public void pagar() {
		this.estado = new CuotaPaga();
		this.fechaDePago = FechaDelDia.hoy();
	}
	
	/**
	 * @return true si la cuota esta vencida
	 */
	public boolean estaVencida() {
		return this.estado.estaVencida(this);
	}

	/**
	 * @return true si la cuota esta pagada
	 */
	public boolean estaPaga() {
		return this.estado.estaPaga();
	}
	
	/**
	 * Imprime el prestamo en XML.
	 */
	@Override
	public void imprimirEnXML() {
		XMLParser.crearCuota(this.getCuotaNumero(), this.getVencimiento().toString(), this.getAmortizacion(), this.getInteres(), this.getSaldoDeDeuda(), 
				this.getSeguro(), this.gastosMensuales, this.getValorCuota(), this.getValorTotalCuota(), fechaDePago, this.getInteresPorMora());
	}

	@Override
	public void imprimirEnHTML() {
		HTMLParser.crearCuota(this.getCuotaNumero(), this.getVencimiento().toString(), this.getAmortizacion(), this.getInteres(), this.getSaldoDeDeuda(), 
				this.getSeguro(), this.gastosMensuales, this.getValorCuota(), this.getValorTotalCuota(), this.getFechaDePago(), this.getInteresPorMora());
	}
	
	private void setAmortizacion(double amortizacion) {
		this.amortizacion = amortizacion;
	}
	
	public double getInteresPorMora() {
		return interesPorMora;
	}
	
	private void setInteresPorMora(double interesPorMora) {
		this.interesPorMora = interesPorMora;
	}
	
	private void setGastosMensuales(double gastosMensuales) {
		this.gastosMensuales = gastosMensuales;
	}
	
	public double getCoeficienteSeguroVida() {
		return coeficienteSeguroVida;
	}
	
	protected void setSeguro(double seguro) {
		this.seguro = seguro;
	}
	
	public double getGastosMensuales() {
		return gastosMensuales;
	}
	
	public double getSeguro() {
		return seguro;
	}
	
	public double getInteres() {
		return interes;
	}
	
	private void setValorTotalCuota(double valorTotalCuota) {
		this.valorTotalCuota = valorTotalCuota;
	}
	
	public void setVencimiento(LocalDate vencimiento) {
		this.vencimiento = vencimiento;
	}
	
	public double getValorTotalCuota() {
		return valorTotalCuota;
	}
	
	public LocalDate getFechaDePago() {
		return fechaDePago;
	}
	
	public LocalDate getVencimiento() {
		return vencimiento;
	}
	
	public int getCuotaNumero() {
		return cuotaNumero;
	}
	
	private void setCuotaNumero(int cuotaNumero) {
		this.cuotaNumero = cuotaNumero;
	}
	
	public double getValorCuota() {
		return valorCuota;
	}
	
	private void setValorCuota(double valorCuota) {
		this.valorCuota = valorCuota;
	}

	public double getSaldoDeDeuda() {
		return saldoDeDeuda;
	}

	protected void setSaldoDeDeuda(double saldoDeDeuda) {
		this.saldoDeDeuda = saldoDeDeuda;
	}

	protected void setInteres(double interes) {
		this.interes = interes;
	}

	public double getTEM() {
		return TEM;
	}

	/**
	 * Si el seguro de vida se calcula por cuota, suma ese valor al valor de la cuota.
	 * Luego se calculan todos los valores de la cuota al tener ya seteado el valor del seguro
	 */
	public void sumarSeguroDeVidaAlValorDeLaCuota() {
		this.setValorTotalCuota(valorCuota + this.getSeguro()); 
		this.calcularValoresCuota();
	}

	/**
	 * Si el seguro de vida se calcula por promedio, agrega ese valor al valor total de la cuota y al seguro de vida.
	 * Luego se calculan todos los valores de la cuota al tener ya seteado el valor del seguro
	 * @param gastosSeguro
	 */
	public void sumarSeguroDeVidaAlValorDeLaCuota(double gastosSeguro) {
		this.setSeguro(gastosSeguro);
		this.setValorTotalCuota(valorCuota + this.getSeguro()); 
		this.calcularValoresCuota();
	}

}